/*
 * Copyright (c) 2020 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package me.yokeyword.eventbusactivityscope;

import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.AbilityLifecycleCallbacks;
import ohos.aafwk.ability.AbilityPackage;
import ohos.app.ElementsCallback;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.global.configuration.Configuration;
import ohos.utils.PacMap;
import org.greenrobot.eventbus.EventBus;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Ability-scope EventBus.
 */
public class EventBusAbilityScope {
    private static AtomicBoolean sInitialized = new AtomicBoolean(false);
    private static volatile EventBus sInvalidEventBus;

    private static final Map<Ability, LazyEventBusInstance> sAbilityEventBusScopePool = new ConcurrentHashMap<>();

    public static void init(AbilityPackage abilityPackage) {
        if (sInitialized.getAndSet(true)) {
            return;
        }

        abilityPackage.registerCallbacks(new AbilityLifecycleCallbacks() {
            private EventHandler mainHandler = new EventHandler(EventRunner.getMainEventRunner());

            @Override
            public void onAbilityStart(Ability ability) {
                sAbilityEventBusScopePool.put(ability, new LazyEventBusInstance());
            }

            @Override
            public void onAbilityActive(Ability ability) {

            }

            @Override
            public void onAbilityInactive(Ability ability) {

            }

            @Override
            public void onAbilityForeground(Ability ability) {

            }

            @Override
            public void onAbilityBackground(Ability ability) {

            }

            @Override
            public void onAbilityStop(Ability ability) {
                if (!sAbilityEventBusScopePool.containsKey(ability)) return;

                // Make sure Fraction's onDestroy() has been called.
                mainHandler.postTask(() -> sAbilityEventBusScopePool.remove(ability));
            }

            @Override
            public void onAbilitySaveState(PacMap pacMap) {

            }
        }, new ElementsCallback() {
            @Override
            public void onMemoryLevel(int i) {

            }

            @Override
            public void onConfigurationUpdated(Configuration configuration) {

            }
        });
    }

    /**
     * Get the Ability-scope EventBus instance
     * @param ability Ability
     * @return Event Bus attached to the ability
     */
    public static EventBus getDefault(Ability ability) {
        if (ability == null) {
            return invalidEventBus();
        }

        LazyEventBusInstance lazyEventBusInstance = sAbilityEventBusScopePool.get(ability);

        if (lazyEventBusInstance == null) {
            return invalidEventBus();
        }

        return lazyEventBusInstance.getInstance();
    }

    private static EventBus invalidEventBus() {
        if (sInvalidEventBus == null) {
            synchronized (EventBusAbilityScope.class) {
                if (sInvalidEventBus == null) {
                    sInvalidEventBus = new EventBus();

                }
            }
        }
        return sInvalidEventBus;
    }

    static class LazyEventBusInstance {
        private volatile EventBus eventBus;

        EventBus getInstance() {
            if (eventBus == null) {
                synchronized (this) {
                    if (eventBus == null) {
                        eventBus = new EventBus();
                    }
                }
            }
            return eventBus;
        }
    }
}
